package service

import (
	"bytes"
	"context"
	"fmt"
	"io/ioutil"
	"math"
	"mygf2/internal/model/entity"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"strings"

	"github.com/gogf/gf/v2/encoding/gbase64"
	"github.com/gogf/gf/v2/encoding/gjson"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gfile"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/text/gregex"
	"github.com/gogf/gf/v2/text/gstr"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/gogf/gf/v2/util/guid"
)

var (
	XiguaService = xiguaService{}
)

type xiguaService struct{}

func (xg *xiguaService) GetPrefixPattern() (res string) {
	res = `ixigua\.com\/\w+`
	return
}
func (xg *xiguaService) MakeUrl(url string) (res string) {
	return
}
func (xg *xiguaService) GetTags(title string) string {
	//解析出tags
	title = strings.Trim(title, "#")
	tagList := strings.Split(title, "#")
	//fmt.Println(tagList)
	tags := []string{}

	for i := 1; i < len(tagList); i++ {
		tags = append(tags, gstr.TrimAll(tagList[i], SpecialCharacterMask...))
	}
	return strings.Join(tags, ",")
}
func (xg *xiguaService) FormatTitle(title string) string {
	//去掉@后的数据
	strList := strings.Split(title, "@")
	//fmt.Println(strList)
	return strings.TrimSpace(strList[0])
}
func (xg *xiguaService) GatherByAuthor(ctx context.Context, url string) (res []*entity.GatherUrls) {

	return
}
func (xg *xiguaService) Fetch(ctx context.Context, url string, taskChan chan interface{}) (res *entity.GatherUrls) {
	defer func() {
		taskChan <- res
	}()
	//判断匹配嘛
	url = xg.GetUrl(url)
	if url == "" {
		return
	}
	client := &http.Client{
		// return http.ErrUseLastResponse。
		// CheckRedirect: func(req *http.Request, via []*http.Request) error {
		// 	return http.ErrUseLastResponse
		// 	// return nil nil回重定向。
		// },
	}
	//fmt.Println(url)
	//fmt.Println("url", url)
	//请求短连接，获取真实地址
	r, e := g.Client().Get(ctx, url)
	if e != nil {
		return
	}
	//cookies := r.Cookies()
	defer r.Close()
	//g.Log().Error(ctx, cookies)
	fullUrl := r.Request.URL.String()
	//fmt.Println("fullUrl", fullUrl)
	//return
	//手机端匹配
	mobilePattern := `m\.ixigua\.com\/video\/(\w+)\/`
	mobileMatch, err := gregex.MatchString(mobilePattern, fullUrl)
	if err != nil {
		return
	}
	if len(mobileMatch) >= 2 {
		fullUrl = "https://www.ixigua.com/" + mobileMatch[1]
	}
	if !gregex.IsMatchString(`www\.ixigua\.com\/\w+`, fullUrl) {
		return
	}
	var req *http.Request
	req, _ = http.NewRequest("GET", fullUrl, nil)
	// //设置cookie
	// for _, c := range cookies {
	// 	req.AddCookie(c)
	// }
	//设置header
	for k, v := range XiGuaHearders {
		req.Header.Add(k, v)
	}
	resp, err := client.Do(req)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	defer resp.Body.Close()
	b, _ := ioutil.ReadAll(resp.Body)
	html := string(b)
	//g.Log().Debug(ctx, html)
	matechs, err := gregex.MatchString(`<script id=\"SSR_HYDRATED_DATA\">window._SSR_HYDRATED_DATA=(.*?)<\/script>`, html)
	if len(matechs) < 2 || err != nil {
		g.Log().Error(ctx, "匹配出问题", matechs, err)
	}
	jsonInfo := gstr.Replace(matechs[1], "undefined", "null")
	//g.Log().Debug(ctx, jsonInfo)
	j := gjson.New(jsonInfo)
	title := j.Get("anyVideo.gidInformation.packerData.video.title").String()
	photoId := j.Get("anyVideo.gidInformation.gid").String()
	media_type := j.Get("anyVideo.gidInformation.packerData.video.videoResource.dash.media_type").String()
	if media_type != "video" {
		g.Log().Error(ctx, media_type, "不是视频")
		return
	}
	queryData := new(entity.GatherUrls)
	queryData.Source = "xigua"
	queryData.Title = xg.FormatTitle(title)
	queryData.Url = "https://www.ixigua.com/" + photoId
	queryData.OriginId = photoId
	queryData.Width = j.Get("anyVideo.gidInformation.packerData.video.videoResource.dash.dynamic_video.dynamic_video_list.3.vwidth").Int()
	queryData.Height = j.Get("anyVideo.gidInformation.packerData.video.videoResource.dash.dynamic_video.dynamic_video_list.3.vheight").Int()
	//1080p
	nowatermarkUrl := j.Get("anyVideo.gidInformation.packerData.video.videoResource.dash.dynamic_video.dynamic_video_list.3.main_url").String()
	nowatermarkUrl, err = gbase64.DecodeToString(nowatermarkUrl)
	if nowatermarkUrl == "" || err != nil {

		//720p
		nowatermarkUrl = j.Get("anyVideo.gidInformation.packerData.video.videoResource.dash.dynamic_video.dynamic_video_list.2.main_url").String()
		//gutil.Dump(nowatermarkUrl)
		nowatermarkUrl, err = gbase64.DecodeToString(nowatermarkUrl)
		queryData.Width = j.Get("anyVideo.gidInformation.packerData.video.videoResource.dash.dynamic_video.dynamic_video_list.2.vwidth").Int()
		queryData.Height = j.Get("anyVideo.gidInformation.packerData.video.videoResource.dash.dynamic_video.dynamic_video_list.2.vheight").Int()
	}
	if nowatermarkUrl == "" {
		g.Log().Error(ctx, "视频地址未获取到")
		return
	}
	//gutil.Dump(nowatermarkUrl)
	//声音  1080p
	music := j.Get("anyVideo.gidInformation.packerData.video.videoResource.dash.dynamic_video.dynamic_audio_list.0.main_url").String()
	music, err = gbase64.DecodeToString(music)
	if music == "" {
		g.Log().Error(ctx, "声音地址未获取到")
		return
	}
	//gutil.Dump(music)

	queryData.NowatermarkUrl = nowatermarkUrl
	coverImg := j.Get("anyVideo.gidInformation.packerData.pSeries.firstVideo.middle_image.url").String()
	queryData.Cover = coverImg
	duration := j.Get("anyVideo.gidInformation.packerData.video.videoResource.dash.video_duration").Float64()
	queryData.Duration = gconv.Int(math.Ceil(duration))
	queryData.Tags = xg.GetTags(queryData.Title)
	//下载
	localVideo, err := xg.Download(ctx, queryData.NowatermarkUrl)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	localMusic, err := xg.Download(ctx, music)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	//合并音视频
	distVideo, err := xg.MergeVideoAndMusicAndUploadOss(ctx, localVideo, localMusic)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	if distVideo == "" {
		g.Log().Error(ctx, "上传oss出错了")
		return
	}
	queryData.DownloadUrl = distVideo
	queryData.IsDownload = 1
	//下载封面图
	queryData.DownCover, err = xg.DownCoverPic(ctx, queryData.Cover)
	//gutil.Dump(queryData)
	//下一步进行存储数据库吧
	res = GatherUrls().GatherInTable(ctx, queryData)
	return
}
func (xg *xiguaService) DownCoverPic(ctx context.Context, url string) (coverYunPath string, err error) {
	//上传封面图
	if url == "" {
		return
	}
	r, err := g.Client().SetHeaderMap(XiGuaHearders).Get(ctx, url)
	if err != nil {
		return
	}
	coverPath := g.Cfg().MustGet(ctx, "tempPath")

	//fileExt := path.Ext(gatherUrls.Cover)
	//exts := strings.Split(fileExt, "?")
	ext := ".jpg"
	coverFileName := guid.S() + ext
	coverLocalFile := coverPath.String() + coverFileName
	err = gfile.PutBytes(coverLocalFile, r.ReadAll())
	if err != nil {
		g.Log().Error(ctx, "远程下载封面图出错", err)
		return
	} else {
		//上传到oss
		coverFiletmp := "video/gather/" + gtime.Now().Format("Ym") + "/" + coverFileName
		//'video/video/'.$date.'/'.$file['FatherName'].'/'.$file['ChildrenName'].'/'.$now.'_'.$name.'_short.'.$type;
		coverYunPath, err = AliyunOSS.UploadFile(ctx, coverLocalFile, coverFiletmp)
		if err != nil {
			g.Log().Error(ctx, err)
			return
		}
	}

	defer func() {
		//删除本地文件
		err = os.Remove(coverLocalFile)
		if err != nil {
			g.Log().Error(ctx, "删除封面图文件出错", err)
			return
		}
	}()
	return
}
func (xg *xiguaService) MergeVideoAndMusicAndUploadOss(ctx context.Context, video, music string) (ossUrl string, err error) {

	in := bytes.Buffer{}
	outInfo := bytes.Buffer{}
	var stderr bytes.Buffer
	pathInfo := g.Cfg().MustGet(ctx, "tempPath")
	file_name := guid.S() + ".mp4"
	localfile := pathInfo.String() + file_name

	//command := "ffmpeg  -i  " + video + "  -i  " + music + "  -vcodec  copy  -acodec  copy  " + localfile
	//tmp := strings.Split(command, " ")
	//fmt.Println(command)
	//cmd := exec.Command("cmd", "/C", command)
	var cmd *exec.Cmd
	goos := runtime.GOOS

	switch goos {
	case "windows":
		command := fmt.Sprintf("ffmpeg -i %s -i %s -vcodec copy -acodec copy %s", video, music, localfile)
		cmd = exec.Command("cmd", "/C", command)
		break
	case "linux":
		//不知道为什么配置了环境变量还是不行，先写绝对路径
		command := fmt.Sprintf("/usr/local/ffmpeg/ffmpeg-4.1/bin/ffmpeg -i %s -i %s -vcodec copy -acodec copy %s", video, music, localfile)
		//fmt.Println("ln", goos)
		//tmp := strings.Split(command, " ")
		//fmt.Println("ln", tmp)
		//cmd = exec.Command(tmp[0], tmp[1:]...)
		cmd = exec.Command("bash", "-c", command)
		break
	}
	cmd.Stdout = &outInfo
	cmd.Stdin = &in
	cmd.Stderr = &stderr
	err = cmd.Run()
	//g.Log().Error(ctx, outInfo.String())
	if err != nil {
		g.Log().Error(ctx, stderr.String())
		g.Log().Error(ctx, "cmd", err)
		return
	}

	// if err = cmd.Wait(); err != nil {
	// 	g.Log().Error(ctx, err)
	// 	return
	// } else {

	// 	//fmt.Println(cmd.ProcessState.Pid())
	// 	//程序退出code
	// 	//g.Log().Error(ctx, cmd.ProcessState.Sys().(syscall.WaitStatus).ExitCode)
	// 	//输出结果
	// 	g.Log().Error(ctx, outInfo.String())
	// }
	if !gfile.Exists(localfile) {
		g.Log().Error(ctx, "合成文件不存在")
		return
	}
	//上传OSS
	//上传到oss
	yunfiletmp := "video/gather/" + gtime.Now().Format("Ym") + "/" + file_name
	//'video/video/'.$date.'/'.$file['FatherName'].'/'.$file['ChildrenName'].'/'.$now.'_'.$name.'_short.'.$type;
	ossUrl, err = AliyunOSS.UploadFile(ctx, localfile, yunfiletmp)
	if err != nil {
		g.Log().Error(ctx, err.Error())
		return
	}
	defer func() {
		//删除本地文件
		err = os.Remove(video)
		if err != nil {
			g.Log().Error(ctx, "删除原视频文件出错")
		}
		//删除本地文件
		err = os.Remove(music)
		if err != nil {
			g.Log().Error(ctx, "删除原音频文件出错")
		}
		//删除本地文件
		err = os.Remove(localfile)
		if err != nil {
			g.Log().Error(ctx, "删除本地合成视频文件出错")
		}
	}()
	return
}
func (xg *xiguaService) Download(ctx context.Context, url string) (localfile string, err error) {
	r, err := g.Client().SetHeaderMap(XiGuaHearders).Get(ctx, url)
	if err != nil {
		return
	}
	pathInfo := g.Cfg().MustGet(ctx, "tempPath")
	file_name := guid.S() + ".mp4"
	localfile = pathInfo.String() + file_name
	err = gfile.PutBytes(localfile, r.ReadAll())
	if err != nil {
		g.Log().Error(ctx, url, "远程下载出错")
		return
	}
	return
}
func (xg *xiguaService) GetUrl(url string) (res string) {
	pattern := xg.GetPrefixPattern()
	if gregex.IsMatchString(pattern, url) {
		return url
	}
	return
}
